package net.pws.common.persistence.hibernate3;

import java.io.Serializable;

import net.pws.common.persistence.ClearInstruction;
import net.pws.common.persistence.CreateEntityInstruction;
import net.pws.common.persistence.DeleteEntityByIdInstruction;
import net.pws.common.persistence.DeleteEntityInstruction;
import net.pws.common.persistence.FlushInstruction;
import net.pws.common.persistence.MergeCallback;
import net.pws.common.persistence.OptimisticConcurrencyInstruction;
import net.pws.common.persistence.PersistenceInstructionVisitor;
import net.pws.common.persistence.UnusedEntityInstruction;
import net.pws.common.persistence.UpdateEntityInstruction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.StaleStateException;


/**
 *
 */
public class HibernatePersistenceInstructionVisitor implements
                                                   PersistenceInstructionVisitor {
    
    private static final Log log = LogFactory.getLog(HibernatePersistenceInstructionVisitor.class);
    
    private Session session;
    
    public HibernatePersistenceInstructionVisitor(Session session) {
        this.session = session;
    }
    
    public void visit(CreateEntityInstruction instruction) {
        session.save(instruction.getEntity());
    }
    
    public void visit(DeleteEntityByIdInstruction instruction) {
        session.delete(session.load(instruction.getEntityClass(),
                                    (Serializable) instruction.getEntityId()));
    }
    
    public void visit(UnusedEntityInstruction instruction) {
        log.error("evict:" + instruction.getEntity());
        session.evict(instruction.getEntity());
    }
    
    public void visit(DeleteEntityInstruction instruction) {
        session.delete(instruction.getEntity());
    }
    
    public void visit(UpdateEntityInstruction instruction) {
        session.update(instruction.getEntity());
    }
    
    public void visit(ClearInstruction instruction) {
        session.clear();
    }
    
    public void visit(FlushInstruction instruction) {
        session.flush();
    }
    
    /**
     * ���ڲ����˰汾���Ƶ��ֹ���,���Ƚ����ύ,����ύʧ�����׳����쳣Ϊ
     * StaleStateException[StaleObjectStateExceptionΪ����],
     * ����Ϊ�ǰ汾����ʧ��,���ʱ����Ҫ���кϲ�,�ϲ�����������ύ.
     */
    public void visit(OptimisticConcurrencyInstruction instruction) {
        Object target = instruction.getTarget();
        MergeCallback mergeCallback = instruction.getMergeCallback();
        while (true) {
            try {
                mergeCallback.merge(target);
                session.update(target);
                session.flush();
                // ����û���׳��쳣,����Ϊ���³ɹ�,���˳�ѭ��
                break;
            }
            catch (StaleStateException e) {
                log.error("�汾����(�ֹ���)ʧ��,��ʵ���Ѿ��������������!", e);
                session.refresh(target);
            }
        }
    }
    
}
